#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "lockGuard.hpp"

const int g_thread_num = 3;
// 线程池->有一批线程，一批任务，有任务push有任务pop，本质是: 生产消费模型
template<class T>
class ThreadPool
{
private:
    ThreadPool(int thread_num = g_thread_num)
        :_num(thread_num)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
        for(int i = 1; i <= _num; ++i)
        {
            _threads.push_back(new Thread(i, routine, this));
        }
    }
    ThreadPool(const ThreadPool<T> &other) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;

public:
    static ThreadPool<T> *getThreadPool(int num = g_thread_num) // 多线程使用单例的过程
    {
        // 可以有效减少未来必定要进行加锁检测的问题
        // 拦截大量的在已经创建好单例的时候，剩余线程请求单例的而直接访问锁的行为
        // 如果这里不加if，未来任何一个线程想获取单例，都必须调用getThreadPool接口
        // 一定会存在大量的申请和释放锁的行为，这个是无用且浪费资源的
        if (nullptr == thread_ptr) 
        {
            lockGuard lockguard(&mutex);
            // pthread_mutex_lock(&mutex);
            if (nullptr == thread_ptr)
            {
                thread_ptr = new ThreadPool<T>(num);
            }
            // pthread_mutex_unlock(&mutex);
        }
        return thread_ptr;
    }

    void run() // 1. 线程池的整体启动
    {
        for (auto &iter : _threads)
        {
            iter->start();
            std::cout << iter->name() << " 启动成功" << std::endl;
        }
    }

    pthread_mutex_t *getMutex()
    {
        return &lock;
    }
    bool isEmpty()
    {
        return _task_queue.empty();
    }
    void waitCond() // 特定的条件变量下等待
    {
        pthread_cond_wait(&cond, &lock);
    }
    T getTask()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }
    static void *routine(void *args) // 每个线程启动后做的工作 
    {   // 类的成员函数有this指针 -> 两个参数 -> 类型不匹配 -> 所以加static
        // 消费过程 -> 访问_task_queue -> 静态访问不了 -> 构造函数传this指针
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_args;
        while (true)
        {
            T task;
            {
                lockGuard lockguard(tp->getMutex()); // 出花括号自动调用析构，花括号里的接口全是加锁的
                while (tp->isEmpty()) // 空就等待
                {
                    tp->waitCond();
                }
                // 任务队列不为空，读取任务
                task = tp->getTask(); // 是共享的-> 将任务从共享，拿到自己的私有空间
            }
            task(td->_name); // 告诉哪一个线程去处理这个任务就行了
        }
    }

    void pushTask(const T &task) // 2. 任务到来时 -> push进线程池 -> 处理任务
    {
        lockGuard lockguard(&lock); // 加锁，执行完这个函数自动解锁
        _task_queue.push(task); // 生产一个任务
        pthread_cond_signal(&cond); // 唤醒一个线程
    }

    // void joins()
    // {
    //     for (auto &iter : _threads)
    //     {
    //         iter->join();
    //     }
    // }
    ~ThreadPool()
    {
        for (auto &iter : _threads)
        {
            // iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

protected:
    std::vector<Thread *> _threads; // 保存一堆线程的容器
    int _num; // 线程的数量
    std::queue<T> _task_queue; // 任务队列
    pthread_mutex_t lock;
    pthread_cond_t cond;

    static ThreadPool<T> *thread_ptr; // 懒汉模式的单例对象指针
    static pthread_mutex_t mutex; // 单例对象的锁
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::thread_ptr = nullptr; // 定义初始化为空

template <typename T>
pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER; // 定义锁






















// #include <iostream>
// #include <vector>
// #include <string>
// #include <queue>
// #include <unistd.h>
// #include "thread.hpp"
// // #include "lockGuard.hpp"
// // #include "log.hpp"

// const int g_thread_num = 3;
// // 本质是: 生产消费模型
// template <class T>
// class ThreadPool
// {
// public:
//     pthread_mutex_t *getMutex()
//     {
//         return &lock;
//     }
//     bool isEmpty()
//     {
//         return _task_queue.empty();
//     }
//     void waitCond()
//     {
//         pthread_cond_wait(&cond, &lock);
//     }
//     T getTask()
//     {
//         T t = _task_queue.front();
//         _task_queue.pop();
//         return t;
//     }

// private:
    // ThreadPool(int thread_num = g_thread_num) : _num(thread_num)
    // {
    //     pthread_mutex_init(&lock, nullptr);
    //     pthread_cond_init(&cond, nullptr);
    //     for (int i = 1; i <= _num; i++)
    //     {
    //         _threads.push_back(new Thread(i, routine, this));
    //     }
    // }
    // ThreadPool(const ThreadPool<T> &other) = delete;
    // const ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;

// public:
    // // 考虑一下多线程使用单例的过程
    // static ThreadPool<T> *getThreadPool(int num = g_thread_num)
    // {
    //     // 可以有效减少未来必定要进行加锁检测的问题
    //     // 拦截大量的在已经创建好单例的时候，剩余线程请求单例的而直接访问锁的行为
    //     if (nullptr == thread_ptr) 
    //     {
    //         lockGuard lockguard(&mutex);
    //         // 但是，未来任何一个线程想获取单例，都必须调用getThreadPool接口
    //         // 但是，一定会存在大量的申请和释放锁的行为，这个是无用且浪费资源的
    //         // pthread_mutex_lock(&mutex);
    //         if (nullptr == thread_ptr)
    //         {
    //             thread_ptr = new ThreadPool<T>(num);
    //         }
    //         // pthread_mutex_unlock(&mutex);
    //     }
    //     return thread_ptr;
    // }
//     // 1. run()
//     void run()
//     {
//         for (auto &iter : _threads)
//         {
//             iter->start();
//             // std::cout << iter->name() << " 启动成功" << std::endl;
//             logMessage(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
//         }
//     }
//     // 线程池本质也是一个生产消费模型
//     // void *routine(void *args)
//     // 消费过程
//     static void *routine(void *args)
//     {
//         ThreadData *td = (ThreadData *)args;
//         ThreadPool<T> *tp = (ThreadPool<T> *)td->_args;
//         while (true)
//         {
//             T task;
//             {
//                 lockGuard lockguard(tp->getMutex());
//                 while (tp->isEmpty())
//                     tp->waitCond();
//                 // 读取任务
//                 task = tp->getTask(); // 任务队列是共享的-> 将任务从共享，拿到自己的私有空间
//             }
//             task(td->_name);
//             // lock
//             // while(task_queue_.empty()) wait();
//             // 获取任务
//             // unlock

//             // 处理任务
//         }
//     }
//     // 2. pushTask()
//     void pushTask(const T &task)
//     {
//         lockGuard lockguard(&lock);
//         _task_queue.push(task);
//         pthread_cond_signal(&cond);
//     }
//     // test func
//     // void joins()
//     // {
//     //     for (auto &iter : threads_)
//     //     {
//     //         iter->join();
//     //     }
//     // }
//     ~ThreadPool()
//     {
//         for (auto &iter : _threads)
//         {
//             iter->join();
//             delete iter;
//         }
//         pthread_mutex_destroy(&lock);
//         pthread_cond_destroy(&cond);
//     }

// protected:
//     std::vector<Thread *> _threads;
//     int _num;
//     std::queue<T> _task_queue;

    // static ThreadPool<T> *thread_ptr;
    // static pthread_mutex_t mutex;

//     // 方案2:
//     //  queue1,queue2
//     //  std::queue<T> *p_queue, *c_queue
//     //  p_queue->queue1
//     //  c_queue->queue2
//     //  p_queue -> 生产一批任务之后，swap(p_queue,c_queue),唤醒所有线程/一个线程
//     //  当消费者处理完毕的时候，你也可以进行swap(p_queue,c_queue)
//     //  因为我们生产和消费用的是不同的队列，未来我们要进行资源的处理的时候，仅仅是指针

//     pthread_mutex_t lock;
//     pthread_cond_t cond;
// };
// template <typename T>
// ThreadPool<T> *ThreadPool<T>::thread_ptr = nullptr;

// template <typename T>
// pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER;